﻿using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Globalization;
using System.IO;
using System.Web;
using System.Web.Script.Serialization;
using System.Threading;

namespace Vit.Common.Providers.Localization
{
    public class JsonResourceProvider : ILocalizationProvider
    {
        private List<JsonResource> jsonResources;

        public JsonResourceProvider()
        {
            Initialize();
        }

        private void LoadResourceInDirectory(string path)
        {
            DirectoryInfo dir = new DirectoryInfo(path);
            if (dir.Exists)
            {
                foreach (FileInfo fi in dir.GetFiles("*.js"))
                {
                    JsonResource jr = new JsonResource();
                    jr.FileName = fi.FullName;
                    string[] fiNames = fi.Name.Split(new char[] { '.' }, StringSplitOptions.RemoveEmptyEntries);
                    if (fiNames.Length == 3)
                    {
                        jr.AssemblyName = fiNames[0];
                        jr.CultureInfoName = fiNames[1];
                    }
                    else if (fiNames.Length == 2)
                    {
                        jr.AssemblyName = fiNames[0];
                        jr.CultureInfoName = string.Empty;
                    }
                    StreamReader sr = new StreamReader(fi.FullName, Encoding.UTF8);
                    JavaScriptSerializer jsSer = new JavaScriptSerializer();
                    jr.Resources = jsSer.Deserialize<List<JsonResourceItem>>(sr.ReadToEnd());

                    jsonResources.Add(jr);
                    sr.Close();
                    sr.Dispose();
                }
            }
        }

        public List<JsonResource> Resources
        {
            get
            {
                return jsonResources;
            }
        }

        #region ILocalizationProvider Members

        public void Initialize()
        {
            jsonResources = new List<JsonResource>();
            LoadResourceInDirectory(HttpContext.Current.Server.MapPath("/Localizations"));

            DirectoryInfo areaDir = new DirectoryInfo(HttpContext.Current.Server.MapPath("/Areas"));
            foreach (DirectoryInfo sdir in areaDir.GetDirectories())
            {
                DirectoryInfo areaLocDir = sdir.GetDirectories("Localizations", SearchOption.TopDirectoryOnly).FirstOrDefault();
                if (areaLocDir != null && areaLocDir.Exists)
                    LoadResourceInDirectory(areaLocDir.FullName);
            }
        }

        public void ReleaseAllResources()
        {
            if (jsonResources != null)
            {
                jsonResources.Clear();
                jsonResources = null;
            }
        }

        private string NormalizeAssemblyName(string assemblyName)
        {
            return assemblyName.Replace(".", "_");
        }

        public string GetString(string assemblyName, string resourceName)
        {
            return GetString(assemblyName, resourceName, Thread.CurrentThread.CurrentCulture.Name);
        }

        public string GetString<T>(string resourceName)
        {
            return GetString<T>(resourceName, Thread.CurrentThread.CurrentCulture.Name);
        }

        public string GetString(object obj, string resourceName)
        {
            return GetString(obj, resourceName, Thread.CurrentThread.CurrentCulture.Name);
        }

        public string GetString(Type type, string resourceName)
        {
            return GetString(type, resourceName, Thread.CurrentThread.CurrentCulture.Name);
        }

        public string GetString(string assemblyName, string resourceName, string cultureInfo)
        {
            assemblyName = NormalizeAssemblyName(assemblyName);
            JsonResource jr = jsonResources.FirstOrDefault(o => o.AssemblyName == assemblyName && o.CultureInfoName == cultureInfo);
            if (jr == null)
                jr = jsonResources.FirstOrDefault(o => o.AssemblyName == assemblyName && o.CultureInfoName == string.Empty);

            if (jr != null)
            {
                var val = jr.Resources.FirstOrDefault(o => o.Name.ToLower() == resourceName.ToLower());
                if (val != null)
                    return val.Value;
            }
            return resourceName;
        }

        public string GetString<T>(string resourceName, string cultureInfo)
        {
            return GetString(typeof(T), resourceName, cultureInfo);
        }

        public string GetString(object obj, string resourceName, string cultureInfo)
        {
            return GetString(obj.GetType(), resourceName, cultureInfo);
        }

        public string GetString(Type type, string resourceName, string cultureInfo)
        {
            return GetString(type.Namespace, resourceName, cultureInfo);
        }

        public void SetString(string assemblyName, string resourceName, string cultureInfo, string value)
        {
            assemblyName = NormalizeAssemblyName(assemblyName);
            var res = jsonResources.FirstOrDefault(o => o.AssemblyName == assemblyName && o.CultureInfoName == cultureInfo);
            if (res == null)
            {
                var defaultRes = jsonResources.FirstOrDefault(o => o.AssemblyName == assemblyName && o.CultureInfoName == string.Empty);
                if (defaultRes == null)
                    throw new FileNotFoundException("File of default resource of assembly {0} not found.", assemblyName);

                res = new JsonResource() { AssemblyName = assemblyName, CultureInfoName = cultureInfo };
                res.FileName = defaultRes.FileName.Replace(".js", string.Format(".{0}.js", cultureInfo));
                res.Resources = new List<JsonResourceItem>();
                jsonResources.Add(res);
            }
            var r = res.Resources.FirstOrDefault(o => o.Name == resourceName);
            if (r == null)
            {
                if (!string.IsNullOrWhiteSpace(value))
                {
                    r = new JsonResourceItem() { Name = resourceName, Value = value };
                    res.Resources.Add(r);
                }
            }
            else
            {
                if (string.IsNullOrWhiteSpace(value))
                    res.Resources.Remove(r);
                else
                {
                    r.Value = value;
                }
            }
        }

        public void Save()
        {
            foreach (var res in jsonResources)
            {
                if (string.IsNullOrEmpty(res.FileName))
                {
                    continue;
                }

                JavaScriptSerializer jsSer = new JavaScriptSerializer();
                var content = jsSer.Serialize(res.Resources);
                StreamWriter sw = new StreamWriter(res.FileName, false, Encoding.UTF8);
                sw.Write(content);
                sw.Flush();
                sw.Close();
                sw.Dispose();
            }
        }

        public bool SupportRuntimeResourceManagement
        {
            get { return true; }
        }

        #endregion

        #region IProvider Members

        public string Name
        {
            get { return "JsonResourceProvider"; }
        }

        #endregion
    }
    public class JsonResource
    {
        public string AssemblyName { get; set; }
        public string CultureInfoName { get; set; }
        public string FileName { get; set; }
        public List<JsonResourceItem> Resources { get; set; }
    }

    public class JsonResourceItem
    {
        public string Name { get; set; }
        public string Value { get; set; }
    }
}
